Introduce a RouteList class.
authortsteven4 <tsteven4@gmail.com>
Sat, 9 Feb 2019 21:59:09 +0000 (14:59 -0700)
committertsteven4 <tsteven4@gmail.com>
Sat, 9 Feb 2019 21:59:09 +0000 (14:59 -0700)
This is backed by a QueueList class, which
adds iterators for queues.  It is anticipated that
this will be replaced by usage of a more standard
container.

12 files changed:
bend.cc
bend.h
defs.h
interpolate.cc
main.cc
queue.h
route.cc
sort.cc
sort.h
stackfilter.cc
stackfilter.h
transform.cc

diff --git a/bend.cc b/bend.cc
index 38c2e04568250bd9350a1225e3dd8eb648274e4d..d794ee1d67c39996519140d6f2cdb4ee0f2c6a26 100644 (file)
--- a/bend.cc
+++ b/bend.cc
@@ -44,7 +44,7 @@ void BendFilter::init()
     minAngle = strtod(minangleopt, nullptr);
   }
 
-  route_backup(&routes_orig_num, &routes_orig);
+  route_backup(&routes_orig);
   route_flush_all_routes();
 }
 
@@ -158,17 +158,17 @@ void BendFilter::process_route_orig(const route_head* route_orig)
 
 void BendFilter::process()
 {
-  queue* elem, *tmp;
-  QUEUE_FOR_EACH(routes_orig, elem, tmp) {
-    route_head* route_orig = reinterpret_cast<route_head *>(elem);
+  for (auto it = routes_orig->cbegin(); it != routes_orig->cend(); ++it) {
+    auto route_orig = reinterpret_cast<const route_head*>(*it);
     process_route_orig(route_orig);
   }
 }
 
 void BendFilter::deinit()
 {
-  route_flush(routes_orig);
-  xfree(routes_orig);
+  routes_orig->flush();
+  delete routes_orig;
+  routes_orig = nullptr;
 }
 
 #endif // FILTERS_ENABLED
diff --git a/bend.h b/bend.h
index 242d0f78d1ffc4f783b56d0fb24c5efc3265322b..904c02999a1e67844f49c97406e9641460ddcfd4 100644 (file)
--- a/bend.h
+++ b/bend.h
@@ -47,8 +47,7 @@ private:
   double maxDist;
   double minAngle;
 
-  queue* routes_orig = nullptr;
-  int routes_orig_num = 0;
+  RouteList* routes_orig = nullptr;
 
   arglist_t args[3] = {
     {
diff --git a/defs.h b/defs.h
index e7221ce3a29679620a214caec79913aeaf175cea..b9710d6e67b892d91f53d2c97a89f60533818c47 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -609,7 +609,7 @@ waypt_disp_session(const session_t* se, T cb)
 #else
   queue* elem, *tmp;
   QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
-    Waypoint* waypointp = reinterpret_cast<Waypoint *>(elem);
+    Waypoint* waypointp = reinterpret_cast<Waypoint*>(elem);
 #endif
     if ((se == nullptr) || (waypointp->session == se)) {
       if (global_opts.verbose_status) {
@@ -667,12 +667,74 @@ public:
 
 public:
   route_head();
+  // the default copy constructor and assignment operator are not appropriate as we do deep copy of some members,
+  // and we haven't bothered to write an appropriate one.
+  // Catch attempts to use the default copy constructor and assignment operator.
+  route_head(const route_head& other) = delete;
+  route_head& operator=(const route_head& rhs) = delete;
   ~route_head();
 };
 
 typedef void (*route_hdr)(const route_head*);
 typedef void (*route_trl)(const route_head*);
 
+// TODO: Consider using composition instead of private inheritance.
+class RouteList : private QueueList<queue>
+{
+public:
+// FIXME: The interface should NOT depend on the implementation of the list.
+//        Migrate to std::sort using a compare function
+//        typedef bool (*Compare)(const route_head* a, const route_head* b);
+  typedef int (*Compare)(const queue* a, const queue* b);
+
+  RouteList();
+
+  int count() const; // a.k.a. size()
+  int waypt_count() const;
+  void add_head(route_head* rte); // a.k.a. append(), push_back()
+  // FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead,
+  //        and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst().
+  void del_head(route_head* rte); // a.k.a. erase()
+  // FIXME: Generally it is inefficent to use an element pointer or reference to define the insertion point, use iterator instead.
+  void insert_head(route_head* rte, route_head* predecessor); // a.k.a. insert
+  void add_wpt(route_head* rte, Waypoint* wpt, bool synth, const QString& namepart, int number_digits);
+  // FIXME: Generally it is inefficent to use an element pointer or reference to define the insertion point, use iterator instead.
+  void del_wpt(route_head* rte, Waypoint* wpt);
+  void common_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc);
+  void flush(); // a.k.a. clear()
+  void copy(RouteList** dst) const;
+  void restore(RouteList* src);
+  void swap(RouteList& other);
+  void sort(Compare cmp);
+  template <typename T1, typename T2, typename T3>
+  void disp_all(T1 rh, T2 rt, T3 wc);
+  template <typename T2, typename T3>
+  void disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc);
+  template <typename T1, typename T3>
+  void disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc);
+  template <typename T3>
+  void disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc);
+
+  // Only expose methods from our underlying container that won't corrupt our private data.
+  // Our contained element (route_head) also contains a container (waypoint_list), 
+  // and we maintain a total count the elements in these contained containers, i.e.
+  // the total number of waypoints in all the routes in the RouteList.
+  using QueueList<queue>::begin;
+  using QueueList<queue>::end;
+  using QueueList<queue>::cbegin;
+  using QueueList<queue>::cend;
+  using QueueList<queue>::empty; // a.k.a. isEmpty()
+  using QueueList<queue>::front; // a.k.a. first()
+  using QueueList<queue>::back;  // a.k.a. last()
+  using QueueList<queue>::Iterator;
+  using QueueList<queue>::ConstIterator;
+
+private:
+  queue head;
+  int head_ct{0};
+  int waypt_ct{0};
+};
+
 void route_init();
 unsigned int route_waypt_count();
 unsigned int route_count();
@@ -684,13 +746,8 @@ void route_del_head(route_head* rte);
 void track_add_head(route_head* rte);
 void track_del_head(route_head* rte);
 void track_insert_head(route_head* rte, route_head* predecessor);
-route_head* route_find_route_by_name(const char* name);
-route_head* route_find_track_by_name(const char* name);
-void route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits);
-void route_add_wpt(route_head* rte, Waypoint* wpt);
-void track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits);
-void track_add_wpt(route_head* rte, Waypoint* wpt);
-Waypoint* route_find_waypt_by_name(route_head* rh, const char* name);
+void route_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart = "RPT", int number_digits = 3);
+void track_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart = "RPT", int number_digits = 3);
 void route_del_wpt(route_head* rte, Waypoint* wpt);
 void track_del_wpt(route_head* rte, Waypoint* wpt);
 //void route_disp(const route_head* rte, waypt_cb); /* template */
@@ -702,15 +759,17 @@ void route_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_c
 void track_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc);
 void route_flush_all_routes();
 void route_flush_all_tracks();
-void route_flush_all();
-void route_flush(queue* head);
-void route_copy(int* dst_count, int* dst_wpt_count, queue** dst, queue* src);
-void route_append(queue* src);
-void track_append(queue* src);
-void route_backup(signed int* count, queue** head_bak);
-void route_restore(queue* head_bak);
-void track_backup(signed int* count, queue** head_bak);
-void track_restore(queue* head_bak);
+void route_deinit();
+void route_append(RouteList* src);
+void track_append(RouteList* src);
+void route_backup(RouteList** head_bak);
+void route_restore(RouteList* head_bak);
+void route_swap(RouteList& other);
+void route_sort(RouteList::Compare cmp);
+void track_backup(RouteList** head_bak);
+void track_restore(RouteList* head_bak);
+void track_swap(RouteList& other);
+void track_sort(RouteList::Compare cmp);
 computed_trkdata track_recompute(const route_head* trk);
 
 template <typename T>
@@ -721,19 +780,19 @@ route_disp(const route_head* rh, T cb)
 // cb != nullptr, caught with an overload of route_disp
   QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) {
     Waypoint* waypointp;
-    waypointp = reinterpret_cast<Waypoint *>(elem);
+    waypointp = reinterpret_cast<Waypoint*>(elem);
     cb(waypointp);
   }
 }
 
 template <typename T1, typename T2, typename T3>
 void
-common_disp_all(queue* qh, T1 rh, T2 rt, T3 wc)
+RouteList::disp_all(T1 rh, T2 rt, T3 wc)
 {
   queue* elem, *tmp;
-  QUEUE_FOR_EACH(qh, elem, tmp) {
+  QUEUE_FOR_EACH(&head, elem, tmp) {
     const route_head* rhp;
-    rhp = reinterpret_cast<route_head *>(elem);
+    rhp = reinterpret_cast<route_head*>(elem);
 // rh != nullptr, caught with an overload of common_disp_all
     rh(rhp);
     route_disp(rhp, wc);
@@ -744,12 +803,12 @@ common_disp_all(queue* qh, T1 rh, T2 rt, T3 wc)
 
 template <typename T2, typename T3>
 void
-common_disp_all(queue* qh, std::nullptr_t /* rh */, T2 rt, T3 wc)
+RouteList::disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc)
 {
   queue* elem, *tmp;
-  QUEUE_FOR_EACH(qh, elem, tmp) {
+  QUEUE_FOR_EACH(&head, elem, tmp) {
     const route_head* rhp;
-    rhp = reinterpret_cast<route_head *>(elem);
+    rhp = reinterpret_cast<route_head*>(elem);
 // rh == nullptr
     route_disp(rhp, wc);
 // rt != nullptr, caught with an overload of common_disp_all
@@ -759,12 +818,12 @@ common_disp_all(queue* qh, std::nullptr_t /* rh */, T2 rt, T3 wc)
 
 template <typename T1, typename T3>
 void
-common_disp_all(queue* qh, T1 rh, std::nullptr_t /* rt */, T3 wc)
+RouteList::disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc)
 {
   queue* elem, *tmp;
-  QUEUE_FOR_EACH(qh, elem, tmp) {
+  QUEUE_FOR_EACH(&head, elem, tmp) {
     const route_head* rhp;
-    rhp = reinterpret_cast<route_head *>(elem);
+    rhp = reinterpret_cast<route_head*>(elem);
 // rh != nullptr, caught with an overload of common_disp_all
     rh(rhp);
     route_disp(rhp, wc);
@@ -774,12 +833,12 @@ common_disp_all(queue* qh, T1 rh, std::nullptr_t /* rt */, T3 wc)
 
 template <typename T3>
 void
-common_disp_all(queue* qh, std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc)
+RouteList::disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc)
 {
   queue* elem, *tmp;
-  QUEUE_FOR_EACH(qh, elem, tmp) {
+  QUEUE_FOR_EACH(&head, elem, tmp) {
     const route_head* rhp;
-    rhp = reinterpret_cast<route_head *>(elem);
+    rhp = reinterpret_cast<route_head*>(elem);
 // rh == nullptr
     route_disp(rhp, wc);
 // rt == nullptr
@@ -790,18 +849,18 @@ template <typename T1, typename T2, typename T3>
 void
 route_disp_all(T1 rh, T2 rt, T3 wc)
 {
-  extern queue my_route_head;
+  extern RouteList* global_route_list;
 
-  common_disp_all(&my_route_head, rh, rt, wc);
+  global_route_list->disp_all(rh, rt, wc);
 }
 
 template <typename T1, typename T2, typename T3>
 void
 track_disp_all(T1 rh, T2 rt, T3 wc)
 {
-  extern queue my_track_head;
+  extern RouteList* global_track_list;
 
-  common_disp_all(&my_track_head, rh, rt, wc);
+  global_track_list->disp_all(rh, rt, wc);
 }
 
 typedef struct {
@@ -1184,7 +1243,7 @@ double fmt_speed(double, const char** tag);
 /*
  * From nmea.c
  */
-int nmea_cksum(const char*buf);
+int nmea_cksum(const char* buf);
 
 /*
  * Color helpers.
index 92ea665735253027f000a1660fa42ba4e696f4ec..fa8933fc8c4578e9838b0fb124f26d31f4647fd7 100644 (file)
 
 void InterpolateFilter::process()
 {
-  queue* backuproute = nullptr;
-  queue* elem, *tmp, *elem2, *tmp2;
-  int count = 0;
+  RouteList* backuproute = nullptr;
+  queue* elem2, *tmp2;
   double lat1 = 0, lon1 = 0;
   double altitude1 = unknown_alt;
   unsigned int time1 = 0;
   double frac;
 
   if (opt_route) {
-    route_backup(&count, &backuproute);
+    route_backup(&backuproute);
     route_flush_all_routes();
   } else {
-    track_backup(&count, &backuproute);
+    track_backup(&backuproute);
     route_flush_all_tracks();
   }
 
-  if (count == 0) {
+  if (backuproute->empty()) {
     fatal(MYNAME ": Found no routes or tracks to operate on.\n");
   }
 
-  QUEUE_FOR_EACH(backuproute, elem, tmp) {
-    route_head* rte_old = reinterpret_cast<route_head *>(elem);
+  for (auto it = backuproute->cbegin(); it != backuproute->cend(); ++it) {
+    auto rte_old = reinterpret_cast<const route_head*>(*it);
 
     route_head* rte_new = route_head_alloc();
     rte_new->rte_name = rte_old->rte_name;
@@ -139,8 +138,8 @@ void InterpolateFilter::process()
       time1 = wpt->creation_time.toTime_t();
     }
   }
-  route_flush(backuproute);
-  xfree(backuproute);
+  backuproute->flush();
+  delete backuproute;
 }
 
 void InterpolateFilter::init()
diff --git a/main.cc b/main.cc
index 8990f1a24be745901749b75787680deba441ad6c..eb869e25223f5407a2ea5d7c06947980b71108e2 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -213,8 +213,10 @@ main(int argc, char* argv[])
   int opt_version = 0;
   int did_something = 0;
   const char* prog_name = argv[0]; /* argv is modified during processing */
-  queue* wpt_head_bak, *rte_head_bak, *trk_head_bak;   /* #ifdef UTF8_SUPPORT */
-  signed int wpt_ct_bak, rte_ct_bak, trk_ct_bak;       /* #ifdef UTF8_SUPPORT */
+  queue* wpt_head_bak; /* #ifdef UTF8_SUPPORT */
+  RouteList* rte_head_bak, *trk_head_bak; /* #ifdef UTF8_SUPPORT */
+  signed int wpt_ct_bak;  /* #ifdef UTF8_SUPPORT */
+  bool lists_backedup;  /* #ifdef UTF8_SUPPORT */
   QStack<QargStackElement> qargs_stack = QStack<QargStackElement>();
 
   // Create a QCoreApplication object to handle application initialization.
@@ -401,9 +403,7 @@ main(int argc, char* argv[])
 
         cet_convert_init(ovecs->encode, ovecs->fixed_encode);
 
-        wpt_ct_bak = -1;
-        rte_ct_bak = -1;
-        trk_ct_bak = -1;
+        lists_backedup = false;
         rte_head_bak = trk_head_bak = nullptr;
 
         ovecs->wr_init(ofname);
@@ -417,9 +417,10 @@ main(int argc, char* argv[])
            */
           int saved_status = global_opts.verbose_status;
           global_opts.verbose_status = 0;
+          lists_backedup = true;
           waypt_backup(&wpt_ct_bak, &wpt_head_bak);
-          route_backup(&rte_ct_bak, &rte_head_bak);
-          track_backup(&trk_ct_bak, &trk_head_bak);
+          route_backup(&rte_head_bak);
+          track_backup(&trk_head_bak);
 
           cet_convert_strings(nullptr, global_opts.charset, nullptr);
           global_opts.verbose_status = saved_status;
@@ -430,16 +431,12 @@ main(int argc, char* argv[])
 
         cet_convert_deinit();
 
-        if (wpt_ct_bak != -1) {
+        if (lists_backedup) {
           waypt_restore(wpt_ct_bak, wpt_head_bak);
-        }
-        if (rte_ct_bak != -1) {
           route_restore(rte_head_bak);
-          xfree(rte_head_bak);
-        }
-        if (trk_ct_bak != -1) {
+          delete rte_head_bak;
           track_restore(trk_head_bak);
-          xfree(trk_head_bak);
+          delete trk_head_bak;
         }
       }
       break;
@@ -720,7 +717,7 @@ main(int argc, char* argv[])
 
   cet_deregister();
   waypt_flush_all();
-  route_flush_all();
+  route_deinit();
   session_exit();
   exit_vecs();
   exit_filter_vecs();
diff --git a/queue.h b/queue.h
index 860239ee5527ee81e5df009386cf01b5087c6c7f..cab0c2961efdedc1e133ba62b1ac20ee67ee98f0 100644 (file)
--- a/queue.h
+++ b/queue.h
@@ -21,6 +21,8 @@
 #ifndef QUEUE_H_INCLUDED_
 #define QUEUE_H_INCLUDED_
 
+#include <iterator>
+
 typedef struct queue {
   struct queue* next;
   struct queue* prev;
@@ -61,6 +63,197 @@ queue* dequeue(queue* element);
                (element) != (listhead); \
                (element) = (tmp))
 
+// FIXME: g++ 7.3.0, -O2, with T=route_head yields warnings.
+//        implementing QueueList as a template was meant to 
+//        i) avoid reinterpret_casts all over the code as with QUEUE_FOR_EACH
+//        ii) allow use of range based for loops.
+//        If this isn't fixed then QueueList doesn't need to be a template, T == queue.
+// In file included from defs.h:27:0,
+//                  from bend.cc:23:
+// queue.h: In instantiation of â€˜const T*& QueueList<T>::ConstIterator::operator*() [with T = route_head; QueueList<T>::ConstIterator::reference = const route_head*&]’:
+// bend.cc:162:24:   required from here
+// queue.h:143:14: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
+//        return reinterpret_cast<reference>(ptr_);
+//               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+template <typename T>
+class QueueList
+{
+public:
+
+  QueueList(queue* head, int* ct) : head_{head}, ct_{ct} {}
+
+  class Iterator
+  {
+  public:
+    using iterator_category = std::bidirectional_iterator_tag;
+    using value_type = T*;
+    using difference_type = std::ptrdiff_t;
+    using pointer = T** ;
+    using reference = T* &;
+
+    Iterator() = default;
+    explicit Iterator(queue* p) : ptr_{p} {}
+
+    reference operator*()
+    {
+      return reinterpret_cast<reference>(ptr_);
+    }
+    pointer operator->()
+    {
+      return reinterpret_cast<pointer>(&ptr_);
+    }
+    Iterator& operator++()   // pre-increment
+    {
+      ptr_ = ptr_->next;
+      return *this;
+    }
+    Iterator operator++(int)   // post-increment
+    {
+      Iterator tmp = *this;
+      ++*this;
+      return tmp;
+    }
+    Iterator& operator--()   // pre-decrement
+    {
+      ptr_ = ptr_->prev;
+      return *this;
+    }
+    Iterator operator--(int)   // post-decrement
+    {
+      Iterator tmp = *this;
+      --*this;
+      return tmp;
+    }
+    bool operator==(const Iterator& other) const
+    {
+      return ptr_ == other.ptr_;
+    }
+    bool operator!=(const Iterator& other) const
+    {
+      return ptr_ != other.ptr_;
+    }
+
+  private:
+    queue* ptr_{nullptr};
+  };
+  //friend class Iterator;
+
+  class ConstIterator
+  {
+  public:
+    using iterator_category = std::bidirectional_iterator_tag;
+    using value_type = T*;
+    using difference_type = std::ptrdiff_t;
+    using pointer = const T** ;
+    using reference = const T* &;
+
+    ConstIterator() = default;
+    explicit ConstIterator(const queue* p) : ptr_{p} {}
+
+    reference operator*()
+    {
+      return reinterpret_cast<reference>(ptr_);
+    }
+    pointer operator->()
+    {
+      return reinterpret_cast<pointer>(&ptr_);
+    }
+    ConstIterator& operator++()   // pre-increment
+    {
+      ptr_ = ptr_->next;
+      return *this;
+    }
+    ConstIterator operator++(int)   // post-increment
+    {
+      ConstIterator tmp = *this;
+      ++*this;
+      return tmp;
+    }
+    ConstIterator& operator--()   // pre-decrement
+    {
+      ptr_ = ptr_->prev;
+      return *this;
+    }
+    ConstIterator operator--(int)   // post-decrement
+    {
+      ConstIterator tmp = *this;
+      --*this;
+      return tmp;
+    }
+    bool operator==(const ConstIterator& other) const
+    {
+      return ptr_ == other.ptr_;
+    }
+    bool operator!=(const ConstIterator& other) const
+    {
+      return ptr_ != other.ptr_;
+    }
+
+  private:
+    const queue* ptr_{nullptr};
+  };
+  //friend class ConstIterator;
+
+  Iterator begin()
+  {
+    return Iterator(head_->next);
+  }
+  ConstIterator begin() const
+  {
+    return ConstIterator(head_->next);
+  }
+  Iterator end()
+  {
+    return Iterator(head_);
+  }
+  ConstIterator end() const
+  {
+    return ConstIterator(head_);
+  }
+  ConstIterator cbegin()
+  {
+    return ConstIterator(head_->next);
+  }
+  ConstIterator cend()
+  {
+    return ConstIterator(head_);
+  }
+
+  bool empty() const
+  {
+    return begin() == end();
+  }
+
+  T& front()
+  {
+    return reinterpret_cast<T&>(**begin());
+  }
+
+  const T& front() const
+  {
+    return reinterpret_cast<const T&>(**begin());
+  }
+
+  T& back()
+  {
+    auto tmp = end();
+    --tmp;
+    return reinterpret_cast<T&>(**tmp);
+  }
+
+  const T& back() const
+  {
+    auto tmp = end();
+    --tmp;
+    return reinterpret_cast<const T&>(**tmp);
+  }
+
+private:
+  queue* head_;
+  int* ct_;
+};
+
+
 /*
  * The following sorting code was derived from linked-list mergesort
  * sample code by Simon Tatham, code obtained from:
index 3707dfb66ea0706846b490f20907deabffe75461..62ac2b4299718a314b88898a44f29f6fcdc56645 100644 (file)
--- a/route.cc
+++ b/route.cc
  */
 
 #include "defs.h"
-#include "grtcirc.h"
-#include "session.h"
-#include <cstdio>
-
-queue my_route_head;
-queue my_track_head;
-static int rte_head_ct;
-static int rte_waypts;
-static int trk_head_ct;
-static int trk_waypts;
+#include "grtcirc.h"            // for RAD, gcdist, heading_true_degrees, radtometers
+#include "queue.h"              // for queue, dequeue, QUEUE_FOR_EACH, QUEUE_MOVE, QUEUE_INIT, sortqueue, ENQUEUE_TAIL, QUEUE_EMPTY, ENQUEUE_AFTER, ENQUEUE_HEAD, QUEUE_LAST, QUEUE_NEXT, QueueList
+#include "session.h"            // for curr_session, session_t (ptr only)
+#include "src/core/datetime.h"  // for DateTime
+#include "src/core/optional.h"  // for optional, operator>, operator<
+#include <QtCore/QDateTime>     // for QDateTime
+#include <QtCore/QString>       // for QString
+#include <cstddef>              // for nullptr_t
+
+RouteList* global_route_list;
+RouteList* global_track_list;
 
 extern void update_common_traits(const Waypoint* wpt);
 
 void
 route_init()
 {
-  QUEUE_INIT(&my_route_head);
-  QUEUE_INIT(&my_track_head);
+  global_route_list = new RouteList;
+  global_track_list = new RouteList;
 }
 
 unsigned int
 route_waypt_count()
 {
-  /* total wapoint count -- all routes */
-  return rte_waypts;
+  /* total waypoint count -- all routes */
+  return global_route_list->waypt_count();
 }
 
 unsigned int
 route_count()
 {
-  return rte_head_ct;  /* total # of routes */
+  return global_route_list->count();   /* total # of routes */
 }
 
 unsigned int
 track_waypt_count()
 {
-  /* totaly waypoint count -- all tracks */
-  return trk_waypts;
+  /* total waypoint count -- all tracks */
+  return global_track_list->waypt_count();
 }
 
 unsigned int
 track_count()
 {
-  return trk_head_ct;  /* total # of tracks */
+  return global_track_list->count();   /* total # of tracks */
 }
 
+// FIXME: provide a method to deallocate a head that isn't added onto a route list,
+// or just let the users allocate with new and deallocate with delete.
 route_head*
 route_head_alloc()
 {
-  route_head* rte_head = new route_head;
-  return rte_head;
-}
-
-static void
-any_route_free(route_head* rte)
-{
-  delete rte;
-  rte = nullptr;
-}
-
-static void
-any_route_add_head(route_head* rte, queue* head)
-{
-  ENQUEUE_TAIL(head, &rte->Q);
-}
-
-static void
-any_route_del_head(route_head* rte)
-{
-  dequeue(&rte->Q);
-  any_route_free(rte);
+  return new route_head;
 }
 
 void
 route_add_head(route_head* rte)
 {
-  any_route_add_head(rte, &my_route_head);
-  rte_head_ct++;
+  global_route_list->add_head(rte);
 }
 
 void
 route_del_head(route_head* rte)
 {
-  rte_waypts -= rte->rte_waypt_ct;
-  any_route_del_head(rte);
-  rte_head_ct--;
+  global_route_list->del_head(rte);
 }
 
 void
 track_add_head(route_head* rte)
 {
-  any_route_add_head(rte, &my_track_head);
-  trk_head_ct++;
+  global_track_list->add_head(rte);
 }
 
 void
 track_del_head(route_head* rte)
 {
-  trk_waypts -= rte->rte_waypt_ct;
-  any_route_del_head(rte);
-  trk_head_ct--;
+  global_track_list->del_head(rte);
 }
 
 void
 track_insert_head(route_head* rte, route_head* predecessor)
 {
-  ENQUEUE_AFTER(&predecessor->Q, &rte->Q);
-  trk_head_ct++;
+  global_track_list->insert_head(rte, predecessor);
 }
 
+// FIXME: can we delete this unused and untested code?
+#ifdef DEAD_CODE_IS_REBORN
 static
 route_head*
 common_route_by_name(queue* routes, const char* name)
@@ -135,7 +112,7 @@ common_route_by_name(queue* routes, const char* name)
   queue* elem, *tmp;
 
   QUEUE_FOR_EACH(routes, elem, tmp) {
-    route_head* rte = reinterpret_cast<route_head *>(elem);
+    route_head* rte = reinterpret_cast<route_head*>(elem);
     if (rte->rte_name == name) {
       return rte;
     }
@@ -155,24 +132,10 @@ route_find_track_by_name(const char* name)
 {
   return common_route_by_name(&my_track_head, name);
 }
-
-static void
-any_route_add_wpt(route_head* rte, Waypoint* wpt, int* ct, int synth, const QString& namepart, int number_digits)
-{
-  ENQUEUE_TAIL(&rte->waypoint_list, &wpt->Q);
-  rte->rte_waypt_ct++; /* waypoints in this route */
-  if (ct) {
-    (*ct)++;
-  }
-  if (synth && wpt->shortname.isEmpty()) {
-    wpt->shortname = QString().sprintf("%s%0*d", CSTRc(namepart), number_digits, *ct);
-    wpt->wpt_flags.shortname_is_synthetic = 1;
-  }
-  update_common_traits(wpt);
-}
+#endif
 
 void
-route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits)
+route_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits)
 {
   // First point in a route is always a new segment.
   // This improves compatibility when reading from
@@ -181,18 +144,11 @@ route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int
     wpt->wpt_flags.new_trkseg = 1;
   }
 
-  any_route_add_wpt(rte, wpt, &rte_waypts, 1, namepart, number_digits);
+  global_route_list->add_wpt(rte, wpt, true, namepart, number_digits);
 }
 
 void
-route_add_wpt(route_head* rte, Waypoint* wpt)
-{
-  const char RPT[] = "RPT";
-  route_add_wpt_named(rte, wpt, RPT, 3);
-}
-
-void
-track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits)
+track_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits)
 {
   // First point in a track is always a new segment.
   // This improves compatibility when reading from
@@ -201,55 +157,38 @@ track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int
     wpt->wpt_flags.new_trkseg = 1;
   }
 
-  any_route_add_wpt(rte, wpt, &trk_waypts, 0, namepart, number_digits);
-}
-
-void
-track_add_wpt(route_head* rte, Waypoint* wpt)
-{
-  const char RPT[] = "RPT";
-  track_add_wpt_named(rte, wpt, RPT, 3);
+  // FIXME: It is misleading to accept namepart and number_digits parameters which
+  // are ignored because synth is set to false.
+  global_track_list->add_wpt(rte, wpt, false, namepart, number_digits);
 }
 
+// FIXME: can we delete this unused and untested code?
+#ifdef DEAD_CODE_IS_REBORN
 Waypoint*
 route_find_waypt_by_name(route_head* rh, const char* name)
 {
   queue* elem, *tmp;
 
   QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) {
-    Waypoint* waypointp = reinterpret_cast<Waypoint *>(elem);
+    Waypoint* waypointp = reinterpret_cast<Waypoint*>(elem);
     if (waypointp->shortname == name) {
       return waypointp;
     }
   }
   return nullptr;
 }
-
-static void
-any_route_del_wpt(route_head* rte, Waypoint* wpt, int* ct)
-{
-  if (wpt->wpt_flags.new_trkseg && wpt != reinterpret_cast<Waypoint *>QUEUE_LAST(&rte->waypoint_list)) {
-    Waypoint* wpt_next = reinterpret_cast<Waypoint *>QUEUE_NEXT(&wpt->Q);
-    wpt_next->wpt_flags.new_trkseg = 1;
-  }
-  wpt->wpt_flags.new_trkseg = 0;
-  dequeue(&wpt->Q);
-  rte->rte_waypt_ct--;
-  if (ct) {
-    (*ct)--;
-  }
-}
+#endif
 
 void
 route_del_wpt(route_head* rte, Waypoint* wpt)
 {
-  any_route_del_wpt(rte, wpt, &rte_waypts);
+  global_route_list->del_wpt(rte, wpt);
 }
 
 void
 track_del_wpt(route_head* rte, Waypoint* wpt)
 {
-  any_route_del_wpt(rte, wpt, &trk_waypts);
+  global_track_list->del_wpt(rte, wpt);
 }
 
 void
@@ -262,220 +201,107 @@ void
 route_reverse(const route_head* rte_hd)
 {
   /* Cast away const-ness */
-  route_head* rh = const_cast<route_head*>(rte_hd);
+  auto rh = const_cast<route_head*>(rte_hd);
   queue* elem, *tmp;
   QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) {
     ENQUEUE_HEAD(&rh->waypoint_list, dequeue(elem));
   }
 }
 
-static void
-common_disp_session(const session_t* se, queue* qh, route_hdr rh, route_trl rt, waypt_cb wc)
-{
-  queue* elem, *tmp;
-  QUEUE_FOR_EACH(qh, elem, tmp) {
-    const route_head* rhp = reinterpret_cast<route_head *>(elem);
-    if (rhp->session == se) {
-      if (rh) {
-        (*rh)(rhp);
-      }
-      route_disp(rhp, wc);
-      if (rt) {
-        (*rt)(rhp);
-      }
-    }
-  }
-}
-
 void
 route_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc)
 {
-  common_disp_session(se, &my_route_head, rh, rt, wc);
+  global_route_list->common_disp_session(se, rh, rt, wc);
 }
 
 void
 track_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc)
 {
-  common_disp_session(se, &my_track_head, rh, rt, wc);
-}
-
-static void
-route_flush_q(queue* head)
-{
-  queue* elem, *tmp;
-
-  QUEUE_FOR_EACH(head, elem, tmp) {
-    queue* q = dequeue(elem);
-    any_route_free(reinterpret_cast<route_head *>(q));
-  }
+  global_track_list->common_disp_session(se, rh, rt, wc);
 }
 
 void
 route_flush_all_routes()
 {
-  route_flush_q(&my_route_head);
-  rte_head_ct = 0;
-  rte_waypts = 0;
+  global_route_list->flush();
 }
 
 void
 route_flush_all_tracks()
 {
-  route_flush_q(&my_track_head);
-  trk_head_ct = 0;
-  trk_waypts = 0;
+  global_track_list->flush();
 }
 
 void
-route_flush_all()
+route_deinit()
 {
-  route_flush_all_tracks();
   route_flush_all_routes();
+  route_flush_all_tracks();
+  delete global_route_list;
+  delete global_track_list;
 }
 
 void
-route_flush(queue* head)
+route_append(RouteList* src)
 {
-  queue* elem, *tmp;
-  QUEUE_FOR_EACH(head, elem, tmp) {
-    queue* q = dequeue(elem);
-    any_route_free(reinterpret_cast<route_head *>(q));
-  }
+  src->copy(&global_route_list);
 }
 
 void
-route_copy(int* dst_count, int* dst_wpt_count, queue** dst, queue* src)
+track_append(RouteList* src)
 {
-  queue* elem, *tmp, *elem2, *tmp2;
-  int junk;
-  if (!dst_wpt_count) {
-    dst_wpt_count = &junk;
-  }
-
-  if (!*dst) {
-    *dst = (queue*)xcalloc(1, sizeof(queue));
-    QUEUE_INIT(*dst);
-    *dst_count = 0;
-    *dst_wpt_count = 0;
-  }
-
-  const char RPT[] = "RPT";
-  QUEUE_FOR_EACH(src, elem, tmp) {
-    route_head* rte_old = reinterpret_cast<route_head *>(elem);
-
-    route_head* rte_new = route_head_alloc();
-    rte_new->rte_name = rte_old->rte_name;
-    rte_new->rte_desc = rte_old->rte_desc;
-    rte_new->rte_urls = rte_old->rte_urls;
-    rte_new->fs = fs_chain_copy(rte_old->fs);
-    rte_new->rte_num = rte_old->rte_num;
-    any_route_add_head(rte_new, *dst);
-    QUEUE_FOR_EACH(&rte_old->waypoint_list, elem2, tmp2) {
-      any_route_add_wpt(rte_new, new Waypoint(*reinterpret_cast<Waypoint *>(elem2)), dst_wpt_count, 0, RPT, 3);
-    }
-    (*dst_count)++;
-  }
+  src->copy(&global_track_list);
 }
 
 void
-route_append(queue* src)
+route_backup(RouteList** head_bak)
 {
-  queue* dst = &my_route_head;
-  route_copy(&rte_head_ct, &rte_waypts, &dst, src);
+  global_route_list->copy(head_bak);
 }
 
 void
-track_append(queue* src)
+route_restore(RouteList* head_bak)
 {
-  queue* dst = &my_track_head;
-  route_copy(&trk_head_ct, &trk_waypts, &dst, src);
+  global_route_list->restore(head_bak);
 }
 
 void
-route_backup(signed int* count, queue** head_bak)
-{
-  route_copy(count, nullptr, head_bak, &my_route_head);
-}
-
-static void
-route_restore_hdr(const route_head* rte)
-{
-  (void)rte;
-  rte_head_ct++;
-}
-
-static void
-track_restore_hdr(const route_head* trk)
-{
-  (void)trk;
-  trk_head_ct++;
-}
-
-static void
-route_restore_tlr(const route_head* rte)
-{
-  (void)rte;
-}
-
-static void
-route_restore_wpt(const Waypoint* wpt)
+route_swap(RouteList& other)
 {
-  (void)wpt;
-  rte_waypts++;
+  global_route_list->swap(other);
 }
 
-static void
-track_restore_wpt(const Waypoint* wpt)
+void
+route_sort(RouteList::Compare cmp)
 {
-  (void)wpt;
-  trk_waypts++;
+  global_route_list->sort(cmp);
 }
 
-static void
-common_restore_finish()
+void
+track_backup(RouteList** head_bak)
 {
-  rte_head_ct = 0;
-  trk_head_ct = 0;
-  rte_waypts = 0;
-  trk_waypts = 0;
-  route_disp_all(route_restore_hdr, route_restore_tlr, route_restore_wpt);
-  track_disp_all(track_restore_hdr, route_restore_tlr, track_restore_wpt);
+  global_track_list->copy(head_bak);
 }
 
 void
-route_restore(queue* head_bak)
+track_restore(RouteList* head_bak)
 {
-  if (head_bak == nullptr) {
-    return;
-  }
-
-  route_flush_q(&my_route_head);
-  QUEUE_INIT(&my_route_head);
-  QUEUE_MOVE(&my_route_head, head_bak);
-
-  common_restore_finish();
+  global_track_list->restore(head_bak);
 }
 
 void
-track_backup(signed int* count, queue** head_bak)
+track_swap(RouteList& other)
 {
-  route_copy(count, nullptr, head_bak, &my_track_head);
+  global_track_list->swap(other);
 }
 
 void
-track_restore(queue* head_bak)
+track_sort(RouteList::Compare cmp)
 {
-  if (head_bak == nullptr) {
-    return;
-  }
-
-  route_flush_q(&my_track_head);
-  QUEUE_INIT(&my_track_head);
-  QUEUE_MOVE(&my_track_head, head_bak);
-
-  common_restore_finish();
+  global_track_list->sort(cmp);
 }
 
+// FIXME: can we delete this unused and untested code?
 #ifdef DEAD_CODE_IS_REBORN
 /*
  * Move the entire track queue onto the route queue making no attempt
@@ -494,6 +320,7 @@ routes_to_tracks()
 }
 #endif
 
+// FIXME: can we delete this unused and untested code?
 #ifdef DEAD_CODE_IS_REBORN
 /*
  * Same, but in opposite direction.
@@ -536,8 +363,8 @@ computed_trkdata track_recompute(const route_head* trk)
 //  first.longitude = 0;
 //  first.creation_time = 0;
 
-  QUEUE_FOR_EACH((queue*)&trk->waypoint_list, elem, tmp) {
-    Waypoint* thisw = reinterpret_cast<Waypoint *>(elem);
+  QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) {
+    auto thisw = reinterpret_cast<Waypoint*>(elem);
 
     /*
      * gcdist and heading want radians, not degrees.
@@ -661,3 +488,170 @@ route_head::~route_head()
     fs_chain_destroy(fs);
   }
 }
+
+RouteList::RouteList() : QueueList<queue>(&head, &head_ct)
+{
+  QUEUE_INIT(&head);
+}
+
+int RouteList::count() const
+{
+  return head_ct;
+}
+
+int RouteList::waypt_count() const
+{
+  return waypt_ct;
+}
+
+// rte may or may not contain waypoints in it's waypoint_list.
+// FIXME: In the case that it does, our count of total waypoints won't
+// match until after rte is added.
+// examples are in tests for garmin_txt, gdb, ggv_log, ik3d, navitel, osm.
+void
+RouteList::add_head(route_head* rte)
+{
+  ENQUEUE_TAIL(&head, &rte->Q);
+  ++head_ct;
+}
+
+void
+RouteList::del_head(route_head* rte)
+{
+  waypt_ct -= rte->rte_waypt_ct;
+  dequeue(&rte->Q);
+  delete rte;
+  --head_ct;
+}
+
+void
+RouteList::insert_head(route_head* rte, route_head* predecessor)
+{
+  ENQUEUE_AFTER(&predecessor->Q, &rte->Q);
+  ++head_ct;
+}
+
+// Synthesizing names based on the total number of waypoints in the RouteList makes
+// it advantageous to keep a count of the total number of waypoints in all the routes
+// in the RouteList AND any routes that have had waypoints added but haven't been
+// added themselves yet.
+void
+RouteList::add_wpt(route_head* rte, Waypoint* wpt, bool synth, const QString& namepart, int number_digits)
+{
+  ENQUEUE_TAIL(&rte->waypoint_list, &wpt->Q);
+  rte->rte_waypt_ct++; /* waypoints in this route */
+  ++waypt_ct;
+  if (synth && wpt->shortname.isEmpty()) {
+    wpt->shortname = QString().sprintf("%s%0*d", CSTRc(namepart), number_digits, waypt_ct);
+    wpt->wpt_flags.shortname_is_synthetic = 1;
+  }
+  update_common_traits(wpt);
+}
+
+void
+RouteList::del_wpt(route_head* rte, Waypoint* wpt)
+{
+  if (wpt->wpt_flags.new_trkseg && wpt != reinterpret_cast<Waypoint*>QUEUE_LAST(&rte->waypoint_list)) {
+    auto wpt_next = reinterpret_cast<Waypoint*>QUEUE_NEXT(&wpt->Q);
+    wpt_next->wpt_flags.new_trkseg = 1;
+  }
+  wpt->wpt_flags.new_trkseg = 0;
+  dequeue(&wpt->Q);
+  rte->rte_waypt_ct--;
+  --waypt_ct;
+}
+
+void
+RouteList::common_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc)
+{
+  queue* elem, *tmp;
+  QUEUE_FOR_EACH(&head, elem, tmp) {
+    const route_head* rhp = reinterpret_cast<route_head*>(elem);
+    if (rhp->session == se) {
+      if (rh) {
+        (*rh)(rhp);
+      }
+      route_disp(rhp, wc);
+      if (rt) {
+        (*rt)(rhp);
+      }
+    }
+  }
+}
+
+void
+RouteList::flush()
+{
+  queue* elem, *tmp;
+
+  QUEUE_FOR_EACH(&head, elem, tmp) {
+    queue* q = dequeue(elem);
+    delete reinterpret_cast<route_head*>(q);
+  }
+  head_ct = 0;
+  waypt_ct = 0;
+}
+
+void
+RouteList::copy(RouteList** dst) const
+{
+  queue* elem, *tmp, *elem2, *tmp2;
+
+  if (*dst == nullptr) {
+    *dst = new RouteList;
+  }
+
+  const char RPT[] = "RPT";
+  QUEUE_FOR_EACH(&head, elem, tmp) {
+    auto rte_old = reinterpret_cast<route_head*>(elem);
+
+    route_head* rte_new = route_head_alloc();
+    rte_new->rte_name = rte_old->rte_name;
+    rte_new->rte_desc = rte_old->rte_desc;
+    rte_new->rte_urls = rte_old->rte_urls;
+    rte_new->fs = fs_chain_copy(rte_old->fs);
+    rte_new->rte_num = rte_old->rte_num;
+    (*dst)->add_head(rte_new);
+    QUEUE_FOR_EACH(&rte_old->waypoint_list, elem2, tmp2) {
+      (*dst)->add_wpt(rte_new, new Waypoint(*reinterpret_cast<Waypoint*>(elem2)), false, RPT, 3);
+    }
+  }
+}
+
+void
+RouteList::restore(RouteList* src)
+{
+  if (src == nullptr) {
+    return;
+  }
+
+  flush();
+  QUEUE_MOVE(&head, &src->head);
+
+  head_ct = src->head_ct;
+  src->head_ct = 0;
+  waypt_ct = src->waypt_ct;
+  src->waypt_ct = 0;
+}
+
+void RouteList::swap(RouteList& other)
+{
+  queue tmp_head;
+  QUEUE_MOVE(&tmp_head, &(other.head));
+  QUEUE_MOVE(&(other.head), &(this->head));
+  QUEUE_MOVE(&(this->head), &tmp_head);
+
+  const auto tmp_head_ct = other.head_ct;
+  other.head_ct = this->head_ct;
+  this->head_ct = tmp_head_ct;
+
+  const auto tmp_waypt_ct = other.waypt_ct;
+  other.waypt_ct = this->waypt_ct;
+  this->waypt_ct = tmp_waypt_ct;
+}
+
+void RouteList::sort(Compare cmp)
+{
+  sortqueue(&head, cmp);
+}
+
diff --git a/sort.cc b/sort.cc
index c4242bc3fee7e8c75bd1a546178a9b40e6b352be..1f28e243ec7f52edf7159b81af4737fa2cf7e450 100644 (file)
--- a/sort.cc
+++ b/sort.cc
 #include <QtCore/QString>    // for QString
 #include <cstdlib>           // for abort
 
-extern queue my_route_head;
-extern queue my_track_head;
-
 #if FILTERS_ENABLED
+#define MYNAME "sort"
 
 template <class T>
 inline int sgn(T v)
@@ -64,49 +62,71 @@ int SortFilter::sort_comp_wpt(const queue* a, const queue* b)
   }
 }
 
-int SortFilter::sort_comp_rh(const queue* a, const queue* b)
+int SortFilter::sort_comp_rh_by_description(const queue* a, const queue* b)
 {
   const route_head* x1 = reinterpret_cast<const route_head*>(a);
   const route_head* x2 = reinterpret_cast<const route_head*>(b);
 
-  switch (rh_sort_mode)  {
-  case SortModeRteHd::description:
-    return x1->rte_desc.compare(x2->rte_desc);
-  case SortModeRteHd::name:
-    return x1->rte_name.compare(x2->rte_name);
-  case SortModeRteHd::number:
-    return cmp(x1->rte_num, x2->rte_num);
-  default:
-    abort();
-    return 0; /* Internal caller error. */
-  }
+  return x1->rte_desc.compare(x2->rte_desc);
 }
 
-int SortFilter::SortCompWptFunctor::operator()(const queue* a, const queue* b)
+int SortFilter::sort_comp_rh_by_name(const queue* a, const queue* b)
 {
-  return that->sort_comp_wpt(a, b);
+  const route_head* x1 = reinterpret_cast<const route_head*>(a);
+  const route_head* x2 = reinterpret_cast<const route_head*>(b);
+
+  return x1->rte_name.compare(x2->rte_name);
 }
 
-int SortFilter::SortCompRteHdFunctor::operator()(const queue* a, const queue* b)
+int SortFilter::sort_comp_rh_by_number(const queue* a, const queue* b)
 {
-  return that->sort_comp_rh(a, b);
+  const route_head* x1 = reinterpret_cast<const route_head*>(a);
+  const route_head* x2 = reinterpret_cast<const route_head*>(b);
+
+  return cmp(x1->rte_num, x2->rte_num);
+}
+
+int SortFilter::SortCompWptFunctor::operator()(const queue* a, const queue* b)
+{
+  return that->sort_comp_wpt(a, b);
 }
 
 void SortFilter::process()
 {
   SortCompWptFunctor sort_comp_wpt_f(*this);
-  SortCompRteHdFunctor sort_comp_rh_f(*this);
 
   if (wpt_sort_mode != SortModeWpt::none) {
     sortqueue(&waypt_head, sort_comp_wpt_f);
   }
   if (rte_sort_mode != SortModeRteHd::none) {
-    rh_sort_mode = rte_sort_mode;
-    sortqueue(&my_route_head, sort_comp_rh_f);
+    switch (rte_sort_mode)  {
+    case SortModeRteHd::description:
+      route_sort(SortFilter::sort_comp_rh_by_description);
+      break;
+    case SortModeRteHd::name:
+      route_sort(sort_comp_rh_by_name);
+      break;
+    case SortModeRteHd::number:
+      route_sort(sort_comp_rh_by_number);
+      break;
+    default:
+      fatal(MYNAME ": unknown route sort mode.");
+    }
   }
   if (trk_sort_mode != SortModeRteHd::none) {
-    rh_sort_mode = trk_sort_mode;
-    sortqueue(&my_track_head, sort_comp_rh_f);
+    switch (trk_sort_mode)  {
+    case SortModeRteHd::description:
+      track_sort(sort_comp_rh_by_description);
+      break;
+    case SortModeRteHd::name:
+      track_sort(sort_comp_rh_by_name);
+      break;
+    case SortModeRteHd::number:
+      track_sort(sort_comp_rh_by_number);
+      break;
+    default:
+      fatal(MYNAME ": unknown track sort mode.");
+    }
   }
 }
 
diff --git a/sort.h b/sort.h
index 8bf31b6f028b7580daf24d1f474799af3c4b0583..9e42f7cf4018da762545abbc801d2f739ce34c9f 100644 (file)
--- a/sort.h
+++ b/sort.h
@@ -58,7 +58,6 @@ private:
 
   SortModeRteHd rte_sort_mode = SortModeRteHd::none;   /* How are we sorting these? */
   SortModeRteHd trk_sort_mode = SortModeRteHd::none;   /* How are we sorting these? */
-  SortModeRteHd rh_sort_mode = SortModeRteHd::none;
 
   char* opt_sm_gcid, *opt_sm_shortname, *opt_sm_description, *opt_sm_time;
   char* opt_sm_rtenum, *opt_sm_rtename, *opt_sm_rtedesc;
@@ -109,7 +108,9 @@ private:
   };
 
   int sort_comp_wpt(const queue* a, const queue* b);
-  int sort_comp_rh(const queue* a, const queue* b);
+  static int sort_comp_rh_by_description(const queue* a, const queue* b);
+  static int sort_comp_rh_by_name(const queue* a, const queue* b);
+  static int sort_comp_rh_by_number(const queue* a, const queue* b);
 
   class SortCompWptFunctor
   {
@@ -121,16 +122,6 @@ private:
     SortFilter* that;
   };
 
-  class SortCompRteHdFunctor
-  {
-  public:
-      explicit SortCompRteHdFunctor(SortFilter& obj) : that(&obj) {}
-    int operator()(const queue* a, const queue* b);
-
-  private:
-    SortFilter* that;
-  };
-
 };
 #endif // FILTERS_ENABLED
 #endif // SORT_H_INCLUDED_
index 9e79d3e22c77318c0c0d289a726acbf454e1b7ba..c50f5445d03e504c86be1dbb7e97eea09f8ce491 100644 (file)
 
 void StackFilter::process()
 {
-  struct stack_elt* tmp_elt = nullptr;
+  stack_elt* tmp_elt = nullptr;
   queue* elem = nullptr;
   queue* tmp = nullptr;
   queue tmp_queue;
+  RouteList* route_list_ptr;
 
   if (opt_push) {
-    tmp_elt = (struct stack_elt*)xmalloc(sizeof(struct stack_elt));
+    tmp_elt = new stack_elt;
 
     QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head);
     tmp_elt->waypt_ct = waypt_count();
@@ -49,18 +50,14 @@ void StackFilter::process()
       }
     }
 
-    tmp = nullptr;
-    route_backup(&(tmp_elt->route_count), &tmp);
-    QUEUE_MOVE(&(tmp_elt->routes), tmp);
-    xfree(tmp);
+    route_list_ptr = &(tmp_elt->routes);
+    route_backup(&route_list_ptr);
     if (!opt_copy) {
       route_flush_all_routes();
     }
 
-    tmp = nullptr;
-    track_backup(&(tmp_elt->track_count), &tmp);
-    QUEUE_MOVE(&(tmp_elt->tracks), tmp);
-    xfree(tmp);
+    route_list_ptr = &(tmp_elt->tracks);
+    track_backup(&route_list_ptr);
     if (!opt_copy) {
       route_flush_all_tracks();
     }
@@ -75,13 +72,13 @@ void StackFilter::process()
         waypt_add(reinterpret_cast<Waypoint *>(elem));
       }
       route_append(&(stack->routes));
-      route_flush(&(stack->routes));
+      stack->routes.flush();
       track_append(&(stack->tracks));
-      route_flush(&(stack->tracks));
+      stack->tracks.flush();
     } else if (opt_discard) {
       waypt_flush(&(stack->waypts));
-      route_flush(&(stack->routes));
-      route_flush(&(stack->tracks));
+      stack->routes.flush();
+      stack->tracks.flush();
     } else {
       waypt_flush(&waypt_head);
       QUEUE_MOVE(&(waypt_head), &(stack->waypts));
@@ -92,7 +89,7 @@ void StackFilter::process()
     }
 
     stack = tmp_elt->next;
-    xfree(tmp_elt);
+    delete tmp_elt;
   } else if (opt_swap) {
     tmp_elt = stack;
     while (swapdepth > 1) {
@@ -105,24 +102,13 @@ void StackFilter::process()
     QUEUE_MOVE(&tmp_queue, &(tmp_elt->waypts));
     QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head);
     QUEUE_MOVE(&waypt_head, &tmp_queue);
-
-    QUEUE_MOVE(&tmp_queue, &(tmp_elt->routes));
-    tmp = nullptr;
-    route_backup(&(tmp_elt->route_count), &tmp);
-    QUEUE_MOVE(&(tmp_elt->routes), tmp);
-    xfree(tmp);
-    route_restore(&tmp_queue);
-
-    QUEUE_MOVE(&tmp_queue, &(tmp_elt->tracks));
-    tmp = nullptr;
-    track_backup(&(tmp_elt->track_count), &tmp);
-    QUEUE_MOVE(&(tmp_elt->tracks), tmp);
-    xfree(tmp);
-    track_restore(&tmp_queue);
-
     unsigned int tmp_count = waypt_count();
     set_waypt_count(tmp_elt->waypt_ct);
     tmp_elt->waypt_ct = tmp_count;
+
+    route_swap(tmp_elt->routes);
+
+    track_swap(tmp_elt->tracks);
   }
 }
 
@@ -172,7 +158,7 @@ void StackFilter::deinit()
 
 void StackFilter::exit()
 {
-  struct stack_elt* tmp_elt = nullptr;
+  stack_elt* tmp_elt = nullptr;
 
   if (warnings_enabled && stack) {
     warning(MYNAME " Warning: leftover stack entries; "
@@ -182,7 +168,7 @@ void StackFilter::exit()
     waypt_flush(&(stack->waypts));
     tmp_elt = stack;
     stack = stack->next;
-    xfree(tmp_elt);
+    delete tmp_elt;
   }
 }
 
index 798a52f161e61d100cf175d32649c5774d0843e9..2e88cd7859c5df603274b3a43e26860d6972708d 100644 (file)
@@ -93,15 +93,21 @@ private:
     ARG_TERMINATOR
   };
 
-  struct stack_elt {
+  class stack_elt
+  {
+  public:
+    stack_elt()
+    {
+      QUEUE_INIT(&waypts);
+    }
+
     queue waypts;
-    queue routes;
-    queue tracks;
-    unsigned int waypt_ct;
-    int route_count;
-    int track_count;
-    struct stack_elt* next;
-  }* stack = nullptr;
+    RouteList routes;
+    RouteList tracks;
+    unsigned int waypt_ct{0};
+    stack_elt* next{nullptr};
+  };
+  stack_elt* stack = nullptr;
 
 };
 #endif // FILTERS_ENABLED
index e5d563f70b76fd36445749ae9040a0c3edf97e59..6cadb9358053edc2996c3ca72a7e08790f40bfe7 100644 (file)
@@ -53,10 +53,10 @@ void TransformFilter::transform_waypoints()
     wpt = new Waypoint(*wpt);
     switch (current_target) {
     case 'R':
-      route_add_wpt_named(rte, wpt, RPT, name_digits);
+      route_add_wpt(rte, wpt, RPT, name_digits);
       break;
     case 'T':
-      track_add_wpt_named(rte, wpt, RPT, name_digits);
+      track_add_wpt(rte, wpt, RPT, name_digits);
       break;
     }
   }
@@ -99,9 +99,9 @@ void TransformFilter::transform_any_disp_wpt_cb(const Waypoint* wpt)
 {
   Waypoint* temp = new Waypoint(*wpt);
   if (current_target == 'R') {
-    route_add_wpt_named(current_rte, temp, current_namepart, name_digits);
+    route_add_wpt(current_rte, temp, current_namepart, name_digits);
   } else if (current_target == 'T') {
-    track_add_wpt_named(current_trk, temp, current_namepart, name_digits);
+    track_add_wpt(current_trk, temp, current_namepart, name_digits);
   } else {
     waypt_add(temp);
   }